小弟最近因緣際會下接觸了聊天室,後來查閱了一下目前有 Polling、WebSocket 與 SSE 三種實作方法,這邊比較一下各個方法的差異與特性
Polling 中文翻譯為輪詢,你可能沒聽過,但是你一定用過,其實說白了就是不斷的去呼叫 function
而已,其中又分為 Polling
與 Long Polling
,以下做介紹
Polling 每隔固定的時間就呼叫一次 function
function shortPolling() {
console.log("Short Polling");
}
setInterval(shortPolling, 1000);
Long Polling 則是在 function
返回後再次呼叫該 function
function longPolling() {
setTimeout(function() {
console.log("Long Polling");
longPolling();
}, 1000);
}
longPolling();
WebSocket 是一種網路傳輸協定,在 WebSocket API
中,Client 與 Server 只需要完成一次交握,兩者之間就可以建立永續性的連接,它讓資料能夠更有效率的做交換,後端這邊使用 ws 做Demo
// 載入 ws
const WebSocket = require("ws");
// 設定 WebSocket
const wss = new WebSocket.Server({ port: 3000 });
// WebSocket API
wss.on("connection", function connection(ws) {
// 接收 Client 端訊息
ws.on("message", function incoming(message) {
console.log(message);
});
// 傳送 Server 端訊息
ws.send("我是 Server");
});
// WebSocket API
const ws = new WebSocket("ws://localhost:3000");
// 連接 API 並傳送 Client 端訊息
ws.onopen = function() {
ws.send("我是 Client");
};
// 接收 Server 端訊息
ws.onmessage = function(e) {
console.log(e.data);
};
如果前端需要訂閱某個 Channel 寫法如下
const ws = new WebSocket("ws://localhost:3000");
ws.onopen = function() {
// 增加以下兩行,ChannelName 改為訂閱的頻道名稱
const subscribe = { command: 'subscribe', identifier: '{"channel":"ChannelName"}' }
ws.send(JSON.stringify(subscribe))
};
ws.onmessage = function(e) {
console.log(e.data);
};
SSE 是 HTML5 標準的 API,他在 Client 連接至 Server 後,透過一般的 http 協定主動將資料推送至 Client,並且不會斷開連接,使用時須要按照規定的格式,先我們先認識一下寫法
前方加上 data:
,資料結尾須加上 \n\n
,若只有 \n
為換行
// 單行
data: message\n\n
// 多行
data: first message\n
data: second message\n\n
當連線意外中斷後,如果有設定 retry:
時間,則時間一到會重新連線
// 中斷連線後5秒重新連結
retry: 5000\n
指定事件名稱時可使用 event:
來做,預設為 message
event: myEvent\n
// 載入 express 與 cors
const express = require("express");
const cors = require("cors");
const app = express();
// 使用 cors 套件
app.use(cors());
// 設定 SSE API
app.get("/", function(req, res) {
// 設定 SSE header
res.header({
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
Connection: "keep-alive"
});
// 設定重新連接時間
res.write("retry: 1000\n");
let data = {
name: "ares",
time: null
};
// 每隔3秒傳送一次資料
setInterval(() => {
defaultEvent();
myEvent();
}, 3000);
// 預設事件 - message
function defaultEvent() {
data.time = new Date();
res.write(`data: ${JSON.stringify(data)}\n\n`);
}
// 自訂事件 - myEvent
function myEvent() {
data.time = new Date();
res.write("event: myEvent\n");
res.write(`data: ${JSON.stringify(data)}\n\n`);
}
});
// 監聽 3000 port
app.listen(3000);
// SSE API
const sse = new EventSource("http://localhost:3000");
// 連接時觸發此事件
sse.addEventListener("open", e => console.log("開啟連接"));
// 連線中斷或其他錯誤觸發此事件
sse.addEventListener("error", e => console.log("關閉連接"));
// 預設事件 - message
sse.addEventListener("message", e =>
console.log("message:", JSON.parse(e.data))
);
// 自訂事件 - myEvent
sse.addEventListener("myEvent", e =>
console.log("myEvent:", JSON.parse(e.data))
);
// 設定十秒後關閉連接
setTimeout(() => {
sse.close();
}, 10000);
看過這些方法後發現,WebSocket
適合拿來做線上遊戲、聊天室,只是支援度較其他低,而 Polling
適合功能簡單資源度低的地方,SSE
基本上就是 Polling 的升級版,適合拿來做新聞頁面、即時股價的應用,各有各的使用情境~